#ifndef GAME_H
#define GAME_H

#include <iostream>
#include <queue.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include "Constants.h"
#include "Piece.h"
#include "Piece_L.h"
#include "Piece_S.h"
#include "Piece_T.h"
#include "Piece_I.h"
#include "Piece_E.h"
#include "Piece_O.h"

class Game {
public:

    Game(int x, int y, int z) : _x(x), _y(y), _z(z), _score(0), _gameOver(false), _commands() {
    };

    void initializeGame();
    
    void fillField();
    
    void emptyCommands();
    
    void restartGame();

    void update(Axis a, Orientation o, Operation operation);

    void updateAll();

    void rotatePiece(Axis a, Orientation o);

    void movePiece(Axis a, Orientation o);
    
    void getCollisionPosition(Piece* piece);

    void setCurrentPiece(Piece piece) {
        _currentPiece = piece;
    };

    Piece* getCurrentPiece() {
        return &_currentPiece;
    };
	
	Piece* getNextPiece() {
        return &_nextPiece;
    };
    
    Piece getCurrentPieceCopy() {
        return _currentPiece;
    };

    bool getGameOver() {
        return _gameOver;
    };

    int* getField() {
        return _field;
    };

    int getX() {
        return _x;
    }

    int getY() {
        return _y;
    }

    int getZ() {
        return _z;
    };
    
    int getScore() {
        return _score;
    }
   

    void addCommand(const command c) {
        _commands.push(c);
    };

    int getValueAtPosition(int x, int y, int z) {

        if (x < 0 || y < 0 || z < 0 || x >= _x || y >= _y || z >= _z) {
            return 0;
        } else {
            return _field[x + _x * y + _x * _y * z];
        }

    };

    /*
     * @return if the value has been set successfully
     */
    bool setValueAtPosition(int x, int y, int z, int value) {
        if (x < 0 || y < 0 || z < 0 || x >= _x || y >= _y || z >= _z) {
            return false;
        } else {
            _field[x + _x * y + _x * _y * z] = value;
            return true;
        }

    };
    
private:

    int _x;
    int _y;
    int _z;
    int _score;
    int* _field;
    bool _gameOver;
    Piece _currentPiece;
    Piece _nextPiece;
    queue<command> _commands;

    void updateScore(int score);

    int computeScorePlane(int planes);

    bool checkIfValidPosition(Point3f position);

    bool checkIfInsideBoundaries(Point3f position);

    bool checkIfValidMove(Axis a, Orientation o);

    bool checkIfValidRotation(Axis a, Orientation o);

    void insertCurrentPieceIntoField();

    void initializePieces();

    bool moveOneDown();

    void moveAllDown();

    void removePlane(int z);

    bool checkIfPlaneFull(int z);

    void removeFullPlanes();

    bool checkIfGameOver();

    void setNextPiece();

    void initializeField();

};

#endif